import btree4j.BTreeCallback;
import btree4j.BTreeIndex;
import btree4j.BTreeException;
import btree4j.Value;
import btree4j.indexer.BasicIndexQuery;
import btree4j.indexer.IndexQuery;
import btree4j.utils.io.FileUtils;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.List;
import java.util.Scanner;

public class BPlusTreeActiveTest {

    private static BTreeIndex btree;
    private static File tmpFile;

    public static void main(String[] args) {
        try {
            initBTree();
            runInteractiveMenu();
        } catch (BTreeException e) {
            e.printStackTrace();
        }
    }

    private static void initBTree() throws BTreeException {
        // 获取当前项目目录
        String projectDir = System.getProperty("user.dir");
        // 创建一个文件夹来存储索引文件
        File indexDir = new File(projectDir, "index");
        if (!indexDir.exists()) {
            indexDir.mkdirs();
        }
        tmpFile = new File(indexDir, "MultiColumnBtreeTest.idx");
        System.out.println("Generated file path: " + tmpFile.getAbsolutePath());
        //tmpFile.deleteOnExit();
        if (tmpFile.exists()) {
            tmpFile.delete();
        }
        btree = new BTreeIndex(tmpFile);
        btree.init(false);
    }

    private static void printMenu() {
        System.out.println("\nB+ Tree Operations Menu");
        System.out.println("0. Exit");
        System.out.println("1. Insert single data");
        System.out.println("2. Insert data from file");
        System.out.println("3. Search by ID");
        System.out.println("4. Range Search");
        System.out.println("5. Delete data");
        System.out.println("6. Update data");
    }

    private static int getIntInput(Scanner scanner, String prompt) {
        System.out.print(prompt);
        while (!scanner.hasNextInt()) {
            System.out.println("Invalid input. Please enter a number.");
            scanner.next();
            System.out.print(prompt);
        }
        return scanner.nextInt();
    }

    private static void executeChoice(int choice, Scanner scanner) throws BTreeException {
        switch (choice) {
            case 0:
                System.out.println("Exiting...");
                break;
            case 1:
                insertSingleData(scanner);
                break;
            case 2:
                insertDataFromFile(scanner);
                break;
            case 3:
                searchById(scanner);
                break;
            case 4:
                rangeSearch(scanner);
                break;
            case 5:
                deleteData(scanner);
                break;
            case 6:
                updateData(scanner);
                break;
            default:
                System.out.println("Invalid choice. Please try again.");
        }
    }

    private static void insertSingleData(Scanner scanner) throws BTreeException {
        System.out.print("Enter key: ");
        String key = scanner.next();
        System.out.print("Enter value: ");
        String value = scanner.next();

        btree.addValue(new Value(key), new Value(value));
        btree.flush();
        System.out.println("Data inserted successfully.");
    }

    private static void insertDataFromFile(Scanner scanner) throws BTreeException {
        System.out.print("Enter file path: ");
        String filePath = scanner.next();
        File file = new File(filePath);

        if (!file.exists()) {
            System.out.println("File does not exist.");
            return;
        }

        try {
            List<String> lines = Files.readAllLines(file.toPath());
            for (String line : lines) {
                String[] parts = line.split("\\s+");
                if (parts.length >= 2) {
                    btree.addValue(new Value(parts[0]), new Value(parts[1]));
                    btree.flush();
                }
            }
            System.out.println("Data inserted from file successfully.");
        } catch (IOException e) {
            System.out.println("Error reading file: " + e.getMessage());
        }
    }

    private static void searchById(Scanner scanner) throws BTreeException {
        System.out.print("Enter key to search: ");
        String key = scanner.next();
        Value value = btree.getValue(new Value(key));
        if (value != null) {
            System.out.println("Found value: " + value.toString());
        } else {
            System.out.println("Key not found.");
        }
    }

    private static void rangeSearch(Scanner scanner) throws BTreeException {
        System.out.print("Enter start key: ");
        String startKey = scanner.next();
        System.out.print("Enter end key: ");
        String endKey = scanner.next();

        IndexQuery query = new BasicIndexQuery(BasicIndexQuery.BW, new Value(startKey), new Value(endKey));
        btree.search(query, new BTreeCallback() {
            public boolean indexInfo(Value value, long pointer) {
                System.out.println("Key: " + value.toString() + ", Value: " + pointer);
                return true;
            }

            public boolean indexInfo(Value key, byte[] value) {
                String stringValue = new String(value, StandardCharsets.UTF_8);
                System.out.println("Key: " + key.toString() + ", Value: " + stringValue.trim());
                return true;
            }
        });
    }

    private static void deleteData(Scanner scanner) throws BTreeException {
        System.out.print("Enter key to delete: ");
        String key = scanner.next();
        long result = btree.removeValue(new Value(key));
        if (result != BTreeIndex.KEY_NOT_FOUND) {
            System.out.println("Data deleted successfully.");
        } else {
            System.out.println("Key not found.");
        }
        btree.flush();
    }

    private static void updateData(Scanner scanner) throws BTreeException {
        System.out.print("Enter key to update: ");
        String key = scanner.next();
        System.out.print("Enter new value: ");
        String newValue = scanner.next();

        btree.putValue(new Value(key), new Value(newValue));
        btree.flush();
        System.out.println("Data updated successfully.");
    }

    private static void runInteractiveMenu() throws BTreeException {
        Scanner scanner = new Scanner(System.in);
        int choice;

        do {
            printMenu();
            choice = getIntInput(scanner, "Enter your choice: ");
            executeChoice(choice, scanner);
        } while (choice != 0);

        scanner.close();
        btree.close();
    }
}
